#ifndef _SKILLPART_H
#define _SKILLPART_H

#include "Part.h"
#include "Skill/SkillMgr.h"
#define cdTimeIdPre 2000000000

struct SkillCfg;
typedef std::list<CharIDType> cList;
typedef std::vector<uint64_t> vecUint64_t;

class SkillPart : public Part
{
	typedef std::unordered_map<uint32_t, stSkillInfo> mapSkillInfo;
	typedef std::map<uint32_t,SkillBase*> mapSkillFightInfo;
	typedef bool(SkillPart::*pFunc)(const char*, uint32_t);
	typedef std::unordered_map<uint32_t, pFunc> mapMsgFunc;
	typedef std::map<CharIDType, int32_t> mapSkillDamage;

protected:
	mapSkillInfo m_mapskills;				//技能存盘信息
	mapSkillFightInfo m_mapSkillFightInfo;	//技能战斗信息，可能同一个技能有两个战斗实例，技能CD非常短的情况可能出现
	mapMsgFunc   m_mapMsgfunc;				//网络消息
	mapSkillDamage m_mapSkillResultDamage;	//本次技能所受伤的生物和伤害。
	uint64_t m_nNumber;  //用于计数技能战斗信息全局ID
public: //网络消息
	bool C2UseSkill(const char* data, uint32_t len);    //使用技能
	bool C2LevUpSkill(const char* data, uint32_t len);  //技能升级
	bool C2StopUseSkill(const char* data, uint32_t len); //停止使用技能，主要是普工三连招用
	bool C2SyncSkillTargets(const char* data, uint32_t len); //同步技能目标
	bool C2GetBuffList(const char* data, uint32_t len);		 //获取玩家所中buff列表
protected://技能内部调用
	//技能工厂,根据技能ID，生成不同的技能对像
	//@uint32_t skillID   技能配置ID
	//return  技能具体实例指针
	SkillBase * FactoryCreateSkillFightInfo(uint32_t skillID);
public:
	//获获技能对像
	//uint32_t skillID 技能配置ID
	//return   技能对像指针
	SkillBase * GetSkillBySkillID(uint32_t skillID);
	//技能播放完成，移除技能对像
	//@int globelid 技能对像的全局ID，由技能工厂产生
	void     RemoveSkillFightInfo(int globelid);
	//回收技能对像进对像池
	//@SkillBase * pSkill 技能对像指针
	void	 RecyleSkill(SkillBase * pSkill);
	//获取生物指针
	//@CharIDType createCid  生物全局ID
	//return 生物指针
	Creature * GetCreature(CharIDType createCid);
	//获取该技能部件主人位置
	//return 位置信息
	Point3<float>  GetMasterPos();
	//获取技能部件主人朝向
	//return 朝向信息
	Point3<float>  GetMasterDir();
	//获取技能部件主人类型
	//return CharIDType 生物类型
	CharIDType GetMasterCid();
	//获取技能部件主人指针
	//return 生物指针
	Creature * GetMaster();
	//同场景内传送,主要给玩家用于有位移的技能
	//@Point3<float>& dstPos 传送到的目标点
	//return 成功失败
	bool Teleporting(Point3<float>& dstPos);         

	//找指定位置，指定范围内的玩家
	/*
	@const SkillCfg* pSkillmeta 技能配置
	@Point3<float> masterPos     施法者坐标
	@Point3<float> skillDir		 技能拖放方向
	@CharIDType targetCid,       目标唯一ID
	@Point3<float> targetpos	 技能拖放目标点
	@uint32_t damagePoint        拖能伤害时间点，有可能多段伤害用
	@uint32_t focotime           技能冷却时间，暂时没用到
	@cList & tmpList			 返回查找到的生物
	*/
	void  FindCreatures(const SkillCfg* pSkillmeta,Point3<float> masterPos,Point3<float> skillDir, CharIDType targetCid, Point3<float> targetpos, uint32_t damagePoint, uint32_t focotime, cList & tmpList);

	//技能拖放结果
	/*
	@uint32_t skillid 技能配置ID
	@const SkillCfg* pSkillmeta 技能配置行指针
	@uint32_t damagePoint 技能伤害次数
	@uint32_t focotime 技能冷却时间 暂时没用
	@cList & tmpList 技能目标列表，用于计算伤害的目标
	*/
	void  SkillResult(uint32_t skillid, const SkillCfg* pSkillmeta,uint32_t damagePoint, uint32_t focotime, cList & tmpList);

	//无目标对像的，只需要发送状态包的技能结果,这个目标会默认为自己
	/*
	@uint32_t skillid 技能配置ID
	@const SkillCfg* pSkillmeta 技能配置行
	@uint32_t damagePoint 技能伤害次数
	@uint32_t focotime 技能冷却时间
	*/
	void SkillNoTageteResult(uint32_t skillid, const SkillCfg* pSkillmeta, uint32_t damagePoint, uint32_t focotime);
	//分担技能结果,只算一个伤害，分担给其它人
	/*
	@uint32_t skillid 技能配置ID
	@const SkillCfg* pSkillmeta 技能配置行指针
	@CharIDType targetID 目标唯一ID
	@cList & tmpList 用来分担的生物ID
	*/
	void SkillResultShareDamage(uint32_t skillid, const SkillCfg* pSkillmeta,CharIDType targetID, cList & tmpList);

	//技能伤害数值计算
	/*
	@Creature *pSource 施法者
	@UseSkillResult& useResult 技能结果，用于发送消息
	@const SkillCfg* pSkillmeta 技能配置
	@CharIDType targetCid 技能目标ID
	@uint32_t damagePoint 技能伤害次数
	@uint32_t focoTime 冷却时间，暂时没用
	@bool isNeedCalculateMyself 是否包含自己,主要用于加BUFF用,这里一个技能可能会有多个人受伤，这个函数要调多次，而每一次都要判断是否给自己加buff
	这里只是用来区分加过后，后面再次调用时，不用再加了
	*/
	void Calculate(Creature *pSource,UseSkillResult& useResult, const SkillCfg* pSkillmeta, CharIDType targetCid, uint32_t damagePoint, uint32_t focoTime, bool isNeedCalculateMyself);
	//计算特殊怪物受伤害,用于计算指定次数杀死的怪
	/*
	@UseSkillResult& useResult 技能结果
	@const SkillCfg* pSkillmeta 技能配置
	@CharIDType targetCid 目标唯 一ID
	*/
	uint32_t CalulateSpeciaMonsterDamage(UseSkillResult& useResult, const SkillCfg* pSkillmeta, CharIDType targetCid);

	//物理伤害技能命中
	/*
	@Creature *pSource 拖法者
	@UseSkillResult::Target *pClientTarget  用于发送消息到客户端
	@Creature *pTarget 拖法目标
	@const SkillCfg* pskillmeta技能配置
	*/ 
	bool CalculateHitAp(Creature *pSource,UseSkillResult::Target *pClientTarget, Creature *pTarget, const SkillCfg* pskillmeta, uint32_t focoTime);
	//魔法伤害技能命中
	bool CalculateHitMat(Creature *pSource,UseSkillResult::Target *pClientTarget, Creature *pTarget, const SkillCfg* pskillmeta, uint32_t focoTime);
	//物理攻击计算
	uint32_t CalculateAp(Creature *pSource,UseSkillResult::Target *pClientTarget, Creature *pTarget, const SkillCfg* pskillmeta, uint32_t damagePoint, uint32_t focoTime);
	//魔法攻击计算
	uint32_t CalculateMat(Creature *pSource,UseSkillResult::Target *pClientTarget, Creature *pTarget, const SkillCfg* pskillmeta, uint32_t damagePoint, uint32_t focoTime);
	//物理暴击计算
	bool CalculateCritAp(Creature *pSource,UseSkillResult::Target *pClientTarget, Creature *pTarget, int32_t &damage, uint32_t focoTime);
	//魔法暴击计算
	bool CalculateCritMat(Creature *pSource,UseSkillResult::Target *pClientTarget, Creature *pTarget, int32_t &damage, uint32_t focoTime);
	//治疗计算
	uint32_t CalculateHeal(UseSkillResult::Target *pClientTarget, Creature *pTarget, const SkillCfg* pskillmeta, uint32_t damagePoint, uint32_t focoTime);

	//根据技能状态包生效点来加状态包(仅技能部件内部使用) bool isNeedCalcuate   有些状态包是加给自己的，这里标记下，只算一次
	bool StateBagWithDamagePoint(Creature *pSource,const SkillCfg *pSkillmeta, uint32_t lev, UseSkillResult& useResult, Creature* pTarget, uint32_t Point, bool isNeedCalcuate);
	//一次性加全部状态包
	bool StateBagAll(Creature *pSource,const SkillCfg *pSkillmeta, uint32_t lev, UseSkillResult& useResult, Creature* pTarget, bool isNeedCalcuate);

	uint32_t FuncLua(uint32_t skillId, vector<string> vecStr, uint32_t dPoint, CharIDType userCid, CharIDType targetCid, uint32_t focotime);

	//获取技能固定攻击值
	int32_t  GetSkillAttackfix(uint32_t skillID, uint32_t damageCount, Creature * pTargetCreature = NULL);
	//获取技能附加伤害百分比
	int32_t  GetSkillAttackPercent(uint32_t skillID, uint32_t damageCount, Creature * pTargetCreature = NULL);
	//获取状态包参数值
	int32_t  GetStateBagParam(uint32_t skillID, uint32_t bagIndex, uint32_t dameagePoint,Creature * pTargetCreature=NULL,uint32_t skillLev=0);
	//获取状态包时间参数
	int32_t GetStateBagTimeParam(uint32_t skillID, uint32_t bagIndex,Creature * pTargetCreature);
	//获取技能固定伤害值
	int32_t GetSkillHurtFix(uint32_t skillID, uint32_t damageCount, Creature * pTargetCreature = NULL);
	//获取技能附加攻击百分比
	int32_t GetSkillHurtPercent(uint32_t skillID, uint32_t damageCount, Creature * pTargetCreature = NULL);
	//获取技能战斗力
	float GetSkillFightValue(uint32_t skillID);
	//判断状态包是否命中
	bool IsHitStateBag(Creature *pSource,Creature * ptarget, SkillCfgStateBag & cfgStatePra);
protected:
	//根据公式，算出最终值
	double GetValueFromFormula(uint32_t skillid,VEC_INT32 & vParam,Creature * pTargetCreature=NULL,uint32_t skillLev=0);
	//将附加伤害等字符串解析为公式 + 参数格式,传入伤害次数,暂时放这，可以放到字符串公共方法中
	//bool GetFormula(string str, VEC_INT32 &vOutParam)  const;
public://提供外部调用的接口
	
	virtual bool Init(Creature *pMaster, uint32_t partType, CharacterDBInfo* pCharacterDB = nullptr);
	virtual bool UnInit();
	virtual bool OnMsgHandle(uint32_t cmd, const char* data, uint32_t len);
	virtual void OnExecute(uint16_t nEventID, uint64_t nSrcID, uint8_t bySrcType, void *pContext, int32_t nLen);
	virtual void OnTimer(uint32_t nTimerID);
	virtual bool SynOnLogin(PlayerClientInfo& playerInfo);
	virtual void SynCreatureLevUp(CreaturesLevUp& clientLevInfo);
	//uint32_t GetValueFromStringMula(uint32_t skillid, string str);
	//获取CD剩余时间
	int64_t GetSkillLeftCDTime(uint32_t skillId);

	//直接加全部状态包(给外部使用)
	bool AddStateBag(uint32_t skillId, uint32_t lev, Creature* pTarget = nullptr);
	//直接移除状态包
	bool RemoveStateBat(uint32_t skillId);
	//获取技能存盘信息
	std::unordered_map<uint32_t, stSkillInfo>& GetSkillInfo() { return m_mapskills; }
	//获取生物普通攻击技能
	uint32_t GetNormalSkillID();
	void GetNormalSkillID(std::vector<uint32_t>& vec);

	//获取玩家当前等级可用技能列表,注意，不包含普通攻击
	void  GetCanUseSkillID(std::vector<uint32_t> & v);
	void  GetMonsterCanUseSkillID(std::vector<uint32_t> & v);
	bool IsPassiveSkill(const SkillCfg* pConfig);

	stSkillInfo* GetSkillInfo(uint32_t skillId);
	//获取技能实体,一个技能可能有多个战斗对像
	SkillBase * GetFightSkillInfo(uint32_t skillId); 
	uint32_t   GetSkillLev(uint32_t skillId);
	uint32_t   GetMaxPrioritySkill();
	int32_t GetSkillRangtype(uint32_t skillid);
	
	//增加一个技能，注意，这里增加的技能都会存在玩家技能列表中，外面不需要重复调用
	virtual bool AddSkill(uint32_t skillId, uint32_t lev, uint64_t cd = 0, uint32_t priority = 0, bool calcFightPower = true, bool isNoticeClient = true, enSkillSaveType type = enSkillSaveType_Online); //priority为优先级,给怪物AI用
	virtual bool RemoveSkill(uint32_t skillId,bool isNoticeClient=true);
	virtual bool SaveDB(CharacterDBInfo& characterDB);
	//技能本身与生物判断是否能使用
	virtual bool IsCanUseSkill(uint32_t skillId, vecUint64_t* targetCids = nullptr, uint32_t count = 0, Creature * pSource = nullptr);
	//判断技能消耗够不够
	bool IsEnoughCost(uint32_t skillId);
	//判断该技能能否作用在该生物上
	virtual bool IsCanBeAttackBySkill(uint32_t skillId, CharIDType targetCid, Creature * pSource = nullptr);

	//该技能最小攻击距离
	uint32_t GetMinAttack(uint32_t skillId);
	//该技能最大攻击距离
	uint32_t GetMaxAttack(uint32_t skillId);

	//被动技能注册
	void RegisterPassiveSkill(SkillBase* pSkill);

	//玩家技能调用接口,切记只能玩家用
	/*
	@uint32_t skillId 技能配置id
	@vecUint64_t& targetCids 技能目标列表
	@const Point3<float> &dir 技能拖放方向
	@const Point3<float>& targetPos 技能拖放目标点
	*/
	bool BeginUseSkill(uint32_t skillId, vecUint64_t& targetCids, const Point3<float> &dir, const Point3<float>& targetPos);
	//怪物ai调用使用技能接口
	/*
	@uint32_t skillId 技能配置ID
	@vecUint64_t& targetCids 目标唯 一ID
	@const Point3<float> &dir 技能拖放方向
	@const Point3<float>& targetPos 技能拖放目标点
	@return 成功，失败
	*/
	bool BeginCreatureUseSkill(uint32_t skillId, vecUint64_t& targetCids, const Point3<float> &dir, const Point3<float>& targetPos);

	//物品使用技能,都是一次性技能
	bool BeginUseSkillByItem(uint32_t skillId, uint32_t skillLev, Creature* pTarget = nullptr);

	virtual void Update(uint64_t tick){}

	//cdPercent cd百分比(万分位)
	//skillId 技能Id (0为所有技能都减cd)
	bool AddSkillcd(int32_t cdPercent, uint32_t skillId = 0);

	//获取技能方向
	Point3<float> GetSkillDir(uint32_t skillID);

	//获取放技能时的玩家位置,暂时是玩家有位移时，记录放技能的位置
	Point3<float> GetCreaturePreSkillPos(uint32_t skillID);

	//获取技能所加战斗力
	float GetAllSkillFightPower();
	//重置所有技能cd
	void  RefreshAllSkillCDTime();
	//获取等级压制率
	int32_t GetLevelSuppress(Creature * pSource,Creature * pTarget);
public:
	SkillPart();
	virtual ~SkillPart();
};

#endif
